package ii.zjf.week1;

import java.io.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.net.URL;

public class LoadHello extends ClassLoader {

    public static void main(String[] args) throws Throwable {

        Object hello = new LoadHello().findClass("Hello").newInstance();

        //反射初始化类
        hello.getClass().getMethod("hello").invoke(hello);

        //lockup 初始化类
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodHandle helloMethod = lookup.findVirtual(hello.getClass(), "hello", MethodType.methodType(void.class));

        helloMethod.invoke(hello);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] bytes = loadHelloXlass();
        return defineClass(name, bytes, 0, bytes.length);
    }

    /**
     * 读取Hello.xlass
     *
     * @return
     */
    public byte[] loadHelloXlass() {

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        try (InputStream inputStream = LoadHello.class.getClassLoader().getResourceAsStream("week1/Hello.xlass")) {
            byte[] buffer = new byte[1024];
            int i = 0;
            assert inputStream != null;
            while ((i = inputStream.read(buffer)) != -1) {

                for (int k = 0; k < i; k++) {
                    byteArrayOutputStream.write((byte) (255 - buffer[k]));
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        //把文件写出来
        URL resource = LoadHello.class.getClassLoader().getResource("week1");
        assert resource != null;
        File file = new File(resource.getPath() + "/Hello.class");

        byte[] bytes = byteArrayOutputStream.toByteArray();

        FileOutputStream fileOutputStream = null;
        try {
            if (!file.exists()) {
                file.createNewFile();
            }
            fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return bytes;
    }


}
